<?php

/**
 * Bootstrap.php
 *
 * Holds class Bootstrap
 *
 * @package Application
 */

/**
 * Bootstrap
 *
 * Bootstraps application
 *
 * @package Application
 */
class Bootstrap extends Mvc_Controller_Front {

	/**
	 * Constructor
	 *
	 * @return void
	 */
	public function __construct() {
		parent::__construct();

		// Register autoloaders
		spl_autoload_register(array($this, 'autoloadClass'));
		spl_autoload_register(array($this, 'autoloadModel'));

		Benchmark::instance();

		// Create config
		$config = new Config();
		$config->import(APP . 'config/common.php')
		->import(APP . 'config/database.php');

		define("HASH", $this->getHashing($config->get("prefered_hash")->export()));
		define("SALT", $config->get("salt_hash"));

		$db = null;
		try{
			//Open database
			$dsn = $config->get('database')->get('type') . ':dbname=' . $config->get('database')->get('name') . ';host=' . $config->get('database')->get('host');
			$db = new Database($dsn, $config->get('database')->get('user'), $config->get('database')->get('pass'));
		}catch(PDOException $e){
			$db = null;
		}

		if(null === $db){
			try{
				// Create database
				$dsn = $config->get('database')->get('type') . ':host=' . $config->get('database')->get('host');
				$db = new Database($dsn, $config->get('database')->get('user'), $config->get('database')->get('pass'));

				$dbname = $config->get('database')->get('name');
				
				if(!file_exists(APP."setup.sql.php")){
					$dbManager = new DBManager($db);
					$content = $dbManager->createSQLCreateTableDump($dbname);
					
					file_put_contents(APP."setup.sql.php", $content);
				}
				
				$sql = include(APP."setup.sql.php");

				foreach ($sql as $query){
					$query = str_ireplace(":name", $dbname, $query);
					$stmt = $db->prepare($query);
					//$stmt->bindParam(":name", $dbname);
					$stmt->execute();
				}
			}catch(FileException $fe){
				echo "{$fe}";
				
				die("Bootstrap(".__LINE__."): Fatal exception");
			}catch(PDOException $ee){
				echo "{$ee}";
				
				die("Bootstrap(".__LINE__."): Fatal exception");
			}
		}
		$config->remove('database');//unset

		// Create language
		$language = new Language();
		//$language->setLanguagePath(APP . 'lang/' . $config->get('language') . '/');

		// Create log
		$log = new Log($this->_getRequest(), APP . 'logs/common.txt');

		// Set routes
		$routes = new Config();
		$routes->import(APP . 'config/routes.php');

		// Set router paths
		$this->_getRouter()->setBasePath(/*$config->get('base')*/ '')
		->setModulePath(APP . 'modules/');

		// Set default route
		try {
			$defaultRoute = explode('/', $routes->get('_default'));
			$this->_getRouter()->setDefault(array(
		        'module'     => $defaultRoute[0],
		        'controller' => $defaultRoute[1],
		        'action'     => $defaultRoute[2]
			));

			$routes->remove('=_default=');//unset
		}
		catch(Exception $e) {
			// no default route, do nothing
		}

		// Set custom routes
		$this->_getRouter()->setRoute($routes->export());

		// Set controller context
		$controllerContext = new Mvc_Context_Controller();
		$controllerContext->setConfig($config)
		->setDb($db)
		->setLanguage($language)
		->setLog($log)
		->setRequest($this->_getRequest())
		->setRouter($this->_getRouter());

		// Pass both to dispatcher
		$this->_getDispatcher()->setControllerContext($controllerContext);
	}

	/**
	 * Runs application
	 *
	 * @see Mvc_Controller_Front::run()
	 * @return Mvc_Response|string
	 */
	public function run() {
		// Import error routes
		$config = new Config();
		$config->import(APP . 'config/error.php');

		try {
			try {
				$response = parent::run();

				if($response instanceof Mvc_Response) {

					switch($response->getStatus()){
						case 401:return $this->getErrorResponse(
						$this->setErrorRequest($config,401),
						$config,
						401);
						break;

						case 200:return $response;
						break;
					}
				}

				return $this->getErrorResponse(
				$this->setErrorRequest($config,404),
				$config,
				404);

			}
			catch(Exception $e) {
				//exception occured, render 500
				try {

					return $this->getErrorResponse(
					$this->setErrorRequest($config,500)->setParam('exception', $e),
					$config,
					500);
				}
				catch(Exception $e) {
					//exception occured, render plain text
					if(DEVELOPMENT) {
						echo '<pre>';print_r($e);echo '</pre>';
					}

					header('HTTP/1.1 500 Internal Server Error');
					return '500 Internal Server Error';
				}
			}
		}
		catch(ErrorException $ee){
			die("Bootstrap(".__LINE__."): Fatal exception");
		}
	}


	public function returnRun($response){

	}

	/**
	 * @param Config $config
	 * @param int $errorNR
	 * @return Mvc_Request
	 */
	public function setErrorRequest(Config $config, $errorNR){
		$this->_getRequest()->setModule($config->get($errorNR)->get('module'))
		->setController($config->get($errorNR)->get('controller'))
		->setAction($config->get($errorNR)->get('action', $errorNR));
		return $this->_getRequest();
	}

	/**
	 *	@param Mvc_Request $request
	 *	@param Config $config
	 *	@param int $errorNR
	 *	@return Mvc_Response
	 */
	public function getErrorResponse(Mvc_Request $request, Config $config, $errorNR){
		$response = $this->_getDispatcher()->dispatch(APP . 'modules/' . $request->getModule() . DIRECTORY_SEPARATOR . $request->getController() . '.php');

		if($response instanceof Mvc_Response)	return $response;

		//Not found, render manual response
		$response = new Mvc_Response();
		return $response->setStatus($errorNR)->setBody($errorNR . $config->get($errorNR)->get('manual'));
	}
	
	public static function loadDBOrCreateFile(){
		
	}
	
	public static function loadDBOrCreateModels(){
		
	}

	/**
	* Autoloads application classes
	*
	* @param string $class
	* @return boolean
	*/
	public function autoloadClass($class) {
		static $classPath;
		
		if(!$classPath){
			$classPath = rtrim( APP . 'classes' . DIRECTORY_SEPARATOR, '\\/') . DIRECTORY_SEPARATOR;
		}
		
		$file = $classPath . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
		if(file_exists($file)) {
			require_once $file;
			return true;
		}
		return false;
	}

	/**
	* Autoloads application model classes
	*
	* @param string $class
	* @return boolean
	*/
	public function autoloadModel($class) {
		// Get paths (once)
		static $modelPath;

		if(!$modelPath){
			$modelPath = rtrim( APP . 'models' . DIRECTORY_SEPARATOR, '\\/') . DIRECTORY_SEPARATOR;
		}
		
		$file = $modelPath . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
		if(file_exists($file)) {
			require_once $file;
			return true;
		}
		return false;
	}

	/**
	 *
	 */
	private function getHashing($prefered_list = array("sha256","sha256","sha1",",md5")){
		//$prefered_list = array("sha256","sha256","sha1",",md5");
		$available_list = hash_algos();

		$hashing = null;
		foreach($prefered_list as $prefered){
			if(null == $hashing){
				// search for more
				$prefered = strtolower($prefered);
				foreach($available_list as $available){
					if($prefered == strtolower($available)){
						$hashing = $prefered;

						break;
					}
				}
			}
		}

		return $hashing;
	}
}
